home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 2002 Tom Parker (tom@carrott.org),
- Matthias Münch (matthias@amigaworld.de)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- In addition, as a special exception, Tom Parker and Matthias Münch give
- permission to link the code of this program with a TCP stack of your
- choice, any official MUI libraries or classes and any custom MUI classes
- that should be necessary for the operation of this program. This
- exception also gives you permission to distribute linked combinations
- including this software with any of the before-mentioned libraries and
- classes. You must obey the GNU General Public License in all respects for
- all of the code used other than that provided by the before-mentioned
- libraries and classes. As part of this exception you are obliged to
- follow the license terms of the before-mentioned libraries, this license
- does not compel you to follow those terms, but if you do not then you may
- not link with those libraries. If you modify this file, you may extend
- this exception to your version of the file, but you are not obligated to
- do so. If you do not wish to do so, delete this exception statement from
- your version.
- */
- /*
- ** built-in http implementation
- */
-
- #include "common.h"
- #include "network.h"
- #include "madthread.h"
- #include <sys/stat.h>
-
- extern struct Library *SocketBase;
-
- struct connection
- {
- listitem node;
- struct xferdata *xf;
- long key;
- int state;
- long sock;
- int len;
- char buf[4096];
- };
-
- static struct fd_set fds;
- static struct timeval tv = { 0, 0 };
- static long sock = -1;
- static list *waitlist = NULL;
-
- static char TryLater[] = "HTTP/1.0 503 Service Unavailable\r\nServer: Jabberwocky\r\nContent-Length: 15\r\n\r\nTry again later";
- static char NotFound[] = "HTTP/1.0 404 Not Found\r\nServer: Jabberwocky\r\nContent-Length: 14\r\n\r\nFile not found";
- static char Header[] = "HTTP/1.0 200 OK\r\nServer: Jabberwocky HTTPd 1.0\r\nContent-Type: application/octet-stream\r\n";
-
- THREAD_DECL(http_agent);
- static int http_poll(struct connection *c);
- static void http_listen_msg(mthread *mt, int com, APTR data);
- static struct xferdata *http_match(char *name);
-
-
- int http_up(void)
- {
- struct sockaddr_in sin;
- long tmp = 1;
-
- if(sock != -1) return(0);
-
- if(!net_lala()) return(-1);
-
- sock = socket(AF_INET, SOCK_STREAM, 0);
- if(sock < 0)
- {
- sock = -1;
- net_bibi();
- return -2;
- }
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = prf.http_port;
- if(bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
- {
- CloseSocket(sock);
- sock = -1;
- net_bibi();
- return -3;
- }
- listen(sock, 4);
- IoctlSocket(sock, FIOASYNC, (char *)&tmp);
-
- printf("listening...\n");
- return 0;
- }
-
-
- void http_down(void)
- {
- if(sock == -1) return;
- CloseSocket(sock);
- net_bibi();
- sock = -1;
- }
-
-
- void http_listen(void)
- {
- struct sockaddr_in sin;
- long len, news;
- struct connection *c;
-
- if(sock == -1) return;
-
- FD_ZERO(&fds);
- FD_SET(sock, &fds);
- if(WaitSelect(sock+1, &fds, NULL, NULL, &tv, 0) == 1)
- {
- len = sizeof(sin);
- news = accept(sock, (struct sockaddr *)&sin, &len);
- if(news >= 0)
- {
- printf("new connection\n");
- c = malloc(sizeof(struct connection));
- if(c)
- {
- c->key = 0;
- c->state = 0;
- c->sock = news;
- c->len = 0;
- c->buf[0] = '\0';
- list_append(&waitlist, c);
- printf("accepted\n");
- }
- else
- CloseSocket(news);
- }
- }
-
-
- if(waitlist)
- {
- struct connection *c2;
-
- c = list_first(&waitlist);
- while(c)
- {
- c2 = list_next(c);
- if(c->state == 0 && http_poll(c) != 0)
- {
- list_remove(&waitlist, c);
- free(c);
- }
- c = c2;
- }
- }
- }
-
-
- static int http_poll(struct connection *c)
- {
- int tmp;
-
- FD_ZERO(&fds);
- FD_SET(c->sock, &fds);
- if(WaitSelect(c->sock+1, &fds, NULL, NULL, &tv, 0) == 1)
- {
- char *pika = c->buf;
- pika += c->len;
- tmp = recv(c->sock, pika, 1023 - c->len, 0);
- if(tmp <= 0)
- {
- CloseSocket(c->sock);
- return 1;
- }
- else
- {
- char *endval;
- c->len += tmp;
- c->buf[c->len] = '\0';
- if(endval = strstr(c->buf, "\r\n\r\n"))
- {
- char *buf = c->buf, *eol;
- printf("checking header\n");
- while(buf < endval)
- {
- if(isspace(buf[0]))
- {
- buf++;
- continue;
- }
- eol = strchr(buf, '\n');
- if(eol == NULL) eol = endval;
-
- if(eol-buf > 4 && strncmp("GET ", buf, 4) == 0)
- {
- struct xferdata *xf;
- buf += 4;
- strtok(buf, " ");
- while(strchr(buf, '/')) buf = strchr(buf, '/') + 1;
- xf = http_match(buf);
- if(!xf)
- {
- send(c->sock, NotFound, sizeof(NotFound) - 1, 0);
- CloseSocket(c->sock);
- return 1;
- }
- printf("launching server thread\n");
- xf->state = XFER_CONNECTED;
- xfer_refresh(xf);
- c->xf = xf;
- c->key = ReleaseSocket(c->sock, GetUniqueID());
- c->state = 1;
- mt_run(&http_agent, c, http_listen_msg);
- }
-
- buf = eol + 1;
- }
- }
- }
- }
- return 0;
- }
-
-
- static struct xferdata *http_match(char *name)
- {
- struct xferdata *xf;
-
- if(!xfers || !name) return(NULL);
- xf = list_first(&xfers);
- while(xf)
- {
- if(strcmp(xf->name, name) == 0) return(xf);
- xf = list_next(xf);
- }
- return NULL;
- }
-
-
- static void http_listen_msg(mthread *mt, int com, APTR data)
- {
- struct connection *c = mt->data;
-
- switch(com)
- {
- case 42:
- c->xf->state = XFER_ERROR;
- printf("error %d.\n", data);
- xfer_refresh(c->xf);
- break;
-
- case 41:
- c->xf->state = XFER_SENDING;
- xfer_refresh(c->xf);
- break;
-
- case 40:
- c->xf->state = XFER_FINISHED;
- xfer_refresh(c->xf);
- break;
- }
- }
-
-
- #define ABORT(x) { mt_feedback(t, 42, (APTR) x ); goto out; }
-
- THREAD(http_agent)
- {
- mthread *t;
- u_long sigs = 0, netsigmask = 0, msgsigmask;
- struct Library *DOSBase = NULL;
- struct Library *SocketBase = NULL;
- struct sockaddr_in sin;
- long sock = -1, len, tmp = 1, netsig = -1;
- struct fd_set fds;
- struct timeval tv = { 0, 0 };
- struct connection *c;
- BPTR f = NULL;
- struct stat statusbuffer;
-
- t = mt_start();
- if(!t) return;
- c = t->data;
-
- netsig = AllocSignal(-1);
- if(netsig == 1) ABORT(0);
- netsigmask = 1L << netsig;
- msgsigmask = 1L << (t->port->mp_SigBit);
-
- DOSBase = OpenLibrary("dos.library", 0);
- if(!DOSBase) ABORT(1);
-
- SocketBase = OpenLibrary("bsdsocket.library", 0);
- if(!SocketBase) ABORT(2);
- SocketBaseTags(SBTM_SETVAL(SBTC_SIGIOMASK), (ULONG) netsigmask, TAG_DONE);
-
- sock = ObtainSocket((u_long)c->key, AF_INET, SOCK_STREAM, 0);
- if(sock < 0) ABORT(3);
-
- f = Open(c->xf->file, MODE_OLDFILE);
- if(!f) ABORT(4);
-
- send(sock, Header, sizeof(Header) - 1, 0);
-
- if (stat(c->xf->file, &statusbuffer) != -1) {
- if (statusbuffer.st_size > 0) {
- char length[36];
- sprintf(length,"Content-Length: %u\r\n", statusbuffer.st_size);
- send(sock, length, strlen(length), 0);
- }
- }
-
- send(sock, "\r\n", 2, 0);
-
- mt_feedback(t, 41, 0);
- while(1)
- {
- sigs = SetSignal(0, netsigmask | msgsigmask | SIGBREAKF_CTRL_C);
-
- if(sigs & SIGBREAKF_CTRL_C)
- break;
-
- len = Read(f, c->buf, 4095);
- if(len == -1) ABORT(5);
- if(len != 0)
- {
- send(sock, c->buf, len, 0);
- }
- if(len == 0) break;
-
- c->xf->cursize += len;
- }
- mt_feedback(t, 40, 0);
-
- out:
- if(f) Close(f);
- if(sock != -1) CloseSocket(sock);
- if(SocketBase) CloseLibrary(SocketBase);
- if(DOSBase) CloseLibrary(DOSBase);
- if(netsig != -1) FreeSignal(netsig);
- mt_end(t);
- }
-